﻿using System;
using System.Threading;

namespace QQ2564874169.Core.Lock
{
    public class ParallelLockspace : IDisposable
    {
        public int Max { get; set; }
        public bool Running => _index > 0;
        private volatile int _index;
        private bool _disposed;

        public ParallelLockspace(int max)
        {
            if (max < 1)
                throw new ArgumentException("count不能小于1。");
            Max = max;
        }

        public void Dispose()
        {
            _disposed = true;
        }

        public ILockspace Lock(int? timeout = null)
        {
            if (_disposed)
                throw new ObjectDisposedException(nameof(ParallelLockspace));

            DateTime? t = null;
            if (timeout.HasValue)
            {
                t = DateTime.Now.AddSeconds(timeout.Value);
            }
            var waiter = new SpinWait();

            while (_disposed == false)
            {
                if (t.HasValue && t.Value < DateTime.Now)
                {
                    throw new TimeoutException(nameof(Lock));
                }
                if (_index < Max)
                {
                    _index++;
                    break;
                }
                waiter.SpinOnce();
            }

            return new LockImplement(() =>
            {
                _index--;
            });
        }

        private class LockImplement : ILockspace
        {
            private Action _dispose;

            public LockImplement(Action dispose)
            {
                _dispose = dispose;
            }

            public void Dispose()
            {
                _dispose?.Invoke();
            }
        }
    }
}
